// =====================================================================
//  File:		CrmServiceUtility.cs
// =====================================================================
//
//  This file is a modified version of crmserviceutility.cs found in
//  the Microsoft CRM 4.0 SDK Code Samples.
//
//  Copyright (C) Microsoft Corporation.  All rights reserved.
//
//  This source code is intended only as a supplement to Microsoft
//  Development Tools and/or on-line documentation.  See these other
//  materials for detailed information regarding Microsoft code samples.
//
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//
// =====================================================================

using System;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;

namespace XrmLibrary.MsCrm4Adapter.Connections
{
	public class CrmServiceUtility
	{

        /// <summary>
        /// Set up the CRM Service using AD authentication.
        /// </summary>
        /// <param name="crmServerUrl">The CRM server URL.</param>
        /// <param name="organizationName">My Organization</param>
        /// <param name="useImpersonation">if set to <c>true</c> [use impersonation].</param>
        /// <returns>
        /// CrmService configured with AD Authentication
        /// </returns>
		public static Microsoft.Crm.SdkTypeProxy.CrmService GetCrmService(string crmServerUrl, string organizationName, bool useImpersonation = true)
		{
			// Setup the Authentication Token
            CrmAuthenticationToken crmAuthenticationToken = GetCrmAuthenticationTokenForOrganization(organizationName);

            var crmServiceUriBuilder = new UriBuilder(crmServerUrl) { Path = "//MSCRMServices//2007//CrmService.asmx" };

            // Instantiate a CrmService
            var crmService = new CrmService
                                 {
                                     Url = crmServiceUriBuilder.ToString(),
                                     UseDefaultCredentials = true,
                                     Credentials = System.Net.CredentialCache.DefaultCredentials,
                                     CrmAuthenticationTokenValue = crmAuthenticationToken,
                                     UnsafeAuthenticatedConnectionSharing = true
                                 };
            return crmService;
		}


        /// <summary>
        /// Set up the CRM Service using AD authentication.
        /// </summary>
        /// <param name="crmServerUrl">The CRM server URL.</param>
        /// <param name="organizationName">My Organization</param>
        /// <param name="networkCredential">The network credential.</param>
        /// <returns>
        /// CrmService configured with AD Authentication
        /// </returns>
        public static CrmService GetCrmService(string crmServerUrl, string organizationName, System.Net.NetworkCredential networkCredential, bool useImpersonation = true)
        {
            // Setup the Authentication Token
            CrmAuthenticationToken crmAuthenticationToken = GetCrmAuthenticationTokenForOrganization(organizationName);

            var crmServiceUriBuilder = new UriBuilder(crmServerUrl) { Path = "//MSCRMServices//2007//CrmService.asmx" };

            // Instantiate a CrmService
            var crmService = new CrmService
            {
                Url = crmServiceUriBuilder.ToString(),
                UseDefaultCredentials = false,
                Credentials = networkCredential,
                CrmAuthenticationTokenValue = crmAuthenticationToken,
                UnsafeAuthenticatedConnectionSharing = true
            };

            return crmService;
        }

	    /// <summary>
        /// Set up the CRM Metadata Service using AD authentication.
        /// </summary>
        /// <param name="crmServerUrl">The CRM server URL.</param>
        /// <param name="organizationName">Name of the organization.</param>
        /// <returns>
        /// MetadataService configured with AD Authentication
        /// </returns>
        public static Microsoft.Crm.SdkTypeProxy.Metadata.MetadataService GetMetadataService(string crmServerUrl, string organizationName, bool useImpersonation = true)
	    {
	        // Setup the Authentication Token
            CrmAuthenticationToken crmAuthenticationToken = GetCrmAuthenticationTokenForOrganization(organizationName);


	        var metadataServiceUriBuilder = new UriBuilder(crmServerUrl)
	                                            {
	                                                Path = "//MSCRMServices//2007//MetadataService.asmx"
	                                            };

	        var metaDataService = new Microsoft.Crm.SdkTypeProxy.Metadata.MetadataService
	                                  {
	                                      Url = metadataServiceUriBuilder.Uri.ToString(),
	                                      CrmAuthenticationTokenValue = crmAuthenticationToken,
	                                      UseDefaultCredentials = true,
	                                      Credentials = System.Net.CredentialCache.DefaultCredentials,
                                          UnsafeAuthenticatedConnectionSharing = true
	                                  };

	        return metaDataService;
	    }

        /// <summary>
        /// Set up the CRM Metadata Service using AD authentication.
        /// </summary>
        /// <param name="crmServerUrl">The CRM server URL.</param>
        /// <param name="organizationName">Name of the organization.</param>
        /// <param name="networkCredential">The network credential.</param>
        /// <returns>
        /// MetadataService configured with AD Authentication
        /// </returns>
        public static Microsoft.Crm.SdkTypeProxy.Metadata.MetadataService GetMetadataService(string crmServerUrl, string organizationName, System.Net.NetworkCredential networkCredential, bool useImpersonation = true)
        {
            // Setup the Authentication Token
            CrmAuthenticationToken crmAuthenticationToken = GetCrmAuthenticationTokenForOrganization(organizationName);

            var metadataServiceUriBuilder = new UriBuilder(crmServerUrl)
            {
                Path = "//MSCRMServices//2007//MetadataService.asmx"
            };

            var metaDataService = new Microsoft.Crm.SdkTypeProxy.Metadata.MetadataService
            {
                Url = metadataServiceUriBuilder.Uri.ToString(),
                CrmAuthenticationTokenValue = crmAuthenticationToken,
                UseDefaultCredentials = false,
                Credentials = networkCredential,
                UnsafeAuthenticatedConnectionSharing = true
            };

            return metaDataService;
        }

        /// <summary>
        /// Gets the systemuserid for the username of the user you would like to impersonate.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        /*public static Guid GetImpersonationId(string userName)
        {
            ColumnSet cols = new ColumnSet();
            cols.Attributes.Add("systemuserid");

	        ConditionExpression condition = new ConditionExpression
	                                            {
	                                                AttributeName = "domainname",
	                                                Operator = ConditionOperator.Equal,
	                                                Values = new string[] {userName}
	                                            };


            FilterExpression filter = new FilterExpression {FilterOperator = LogicalOperator.And};
            filter.AddCondition(condition);

            QueryExpression userQuery = new QueryExpression
                                            {
                                                EntityName = EntityName.systemuser.ToString(),
                                                ColumnSet = cols,
                                                Criteria = filter
                                            };



            using (CrmService service = GetCrmService(GlobalSettings.Instance.CrmServerUrl, GlobalSettings.Instance.CrmOrganizationName, false))
            {
                BusinessEntityCollection users = service.RetrieveMultiple(userQuery);

                if (users.BusinessEntities.Count <= 0)
                {
                    throw new ApplicationException("There were no users that matched the impersonation users domainname supplied in the app.config.");
                }
                else if (users.BusinessEntities.Count > 1)
                {
                    throw new ApplicationException("There were multiple users that matched the impersonation users domainname supplied in the app.config.");
                }
                else
                {
                    systemuser user = (systemuser)users.BusinessEntities[0];
                    return user.systemuserid.Value;
                }
            }
        }*/

        /// <summary>
        /// Gets the CRM authentication token for user and organization.
        /// </summary>
        /// <param name="user">The string user ID or domain\user of the account to impersonate.</param>
        /// <param name="organizationName">Name of the organization.</param>
        /// <returns></returns>
        public static CrmAuthenticationToken GetCrmAuthenticationTokenForOrganization(string organizationName)
        {
            // Setup the Authentication Token
            CrmAuthenticationToken token = new CrmAuthenticationToken
                                               {
                                                   OrganizationName = organizationName,
                                                   AuthenticationType = AuthenticationType.AD
			                                 };
            return token;
        }
	}
}
